home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '87 / Source ƒ.sea / Source ƒ / emacs source ƒ / INPUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-28  |  11.8 KB  |  545 lines  |  [TEXT/MARC]

  1. /*    INPUT:    Various input routines for MicroEMACS 3.7
  2.         written by Daniel Lawrence
  3.         5/9/86                        */
  4.  
  5. #include    <stdio.h>
  6. #include    "estruct.h"
  7. #include    "edef.h"
  8.  
  9. /*
  10.  * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  11.  * ABORT. The ABORT status is returned if the user bumps out of the question
  12.  * with a ^G. Used any time a confirmation is required.
  13.  */
  14.  
  15. mlyesno(prompt)
  16.  
  17. char *prompt;
  18.  
  19. {
  20.     char c;            /* input character */
  21.     char buf[NPAT];        /* prompt to user */
  22.  
  23.     for (;;) {
  24.         /* build and prompt the user */
  25.         strcpy(buf, prompt);
  26.         strcat(buf, " [y/n]? ");
  27.         mlwrite(buf);
  28.  
  29.         /* get the responce */
  30.         c = (*term.t_getchar)();
  31.  
  32.         if (c == ectoc(abortc))        /* Bail out! */
  33.             return(ABORT);
  34.  
  35.         if (c=='y' || c=='Y')
  36.             return(TRUE);
  37.  
  38.         if (c=='n' || c=='N')
  39.             return(FALSE);
  40.     }
  41. }
  42.  
  43. /*
  44.  * Write a prompt into the message line, then read back a response. Keep
  45.  * track of the physical position of the cursor. If we are in a keyboard
  46.  * macro throw the prompt away, and return the remembered response. This
  47.  * lets macros run at full speed. The reply is always terminated by a carriage
  48.  * return. Handle erase, kill, and abort keys.
  49.  */
  50.  
  51. mlreply(prompt, buf, nbuf)
  52.     char *prompt;
  53.     char *buf;
  54. {
  55.     return(mlreplyt(prompt, buf, nbuf, ctoec('\n')));
  56. }
  57.  
  58. /*    A more generalized prompt/reply function allowing the caller
  59.     to specify the proper terminator. If the terminator is not
  60.     a return ('\n') it will echo as "<NL>"
  61.                             */
  62. mlreplyt(prompt, buf, nbuf, eolchar)
  63.  
  64. char *prompt;
  65. char *buf;
  66. int eolchar;
  67.  
  68. {
  69.     register int cpos;    /* current character position in string */
  70.     register int i;
  71.     register int c;
  72.     register int quotef;    /* are we quoting the next char? */
  73.     register int status;    /* status return value */
  74.  
  75.  
  76.     cpos = 0;
  77.     quotef = FALSE;
  78.  
  79.     if (kbdmop != NULL) {
  80.         while ((c = *kbdmop++) != '\0')
  81.             buf[cpos++] = c;
  82.  
  83.         buf[cpos] = 0;
  84.  
  85.         if (buf[0] == 0)
  86.             return(FALSE);
  87.  
  88.         return(TRUE);
  89.     }
  90.  
  91.     /* check to see if we are executing a command line */
  92.     if (clexec) {
  93.         status = nxtarg(buf);
  94.         buf[nbuf-1] = 0;    /* make sure we null terminate it */
  95.         return(status);
  96.     }
  97.  
  98.     mlwrite(prompt);
  99.  
  100.     for (;;) {
  101.     /* get a character from the user. if it is a <ret>, change it
  102.        to a <NL>                            */
  103.         c = get1key();
  104.         if (c == (CTRL | 0x4d))
  105.             c = CTRL | 0x40 | '\n';
  106.  
  107.         if (c == eolchar && quotef == FALSE) {
  108.             buf[cpos++] = 0;
  109.  
  110.             if (kbdmip != NULL) {
  111.                 if (kbdmip+cpos > &kbdm[NKBDM-3]) {
  112.                     ctrlg(FALSE, 0);
  113.                     (*term.t_flush)();
  114.                     return(ABORT);
  115.                 }
  116.  
  117.                 for (i=0; i<cpos; ++i)
  118.                     *kbdmip++ = buf[i];
  119.             }
  120.  
  121.             (*term.t_move)(term.t_nrow, 0);
  122.             ttcol = 0;
  123.             (*term.t_flush)();
  124.  
  125.             if (buf[0] == 0)
  126.                 return(FALSE);
  127.  
  128.             return(TRUE);
  129.  
  130.         }
  131.  
  132.         /* change from command form back to character form */
  133.         c = ectoc(c);
  134.  
  135.         if (c == ectoc(abortc) && quotef == FALSE) {
  136.             /* Bell, abort */
  137.             ctrlg(FALSE, 0);
  138.             (*term.t_flush)();
  139.             return(ABORT);
  140.  
  141.         } else
  142.             if ((c==0x7F || c==0x08) && quotef==FALSE) {
  143.             /* rubout/erase */
  144.             if (cpos != 0) {
  145.                 (*term.t_putchar)('\b');
  146.                 (*term.t_putchar)(' ');
  147.                 (*term.t_putchar)('\b');
  148.                 --ttcol;
  149.  
  150.                 if (buf[--cpos] < 0x20) {
  151.                     (*term.t_putchar)('\b');
  152.                     (*term.t_putchar)(' ');
  153.                     (*term.t_putchar)('\b');
  154.                     --ttcol;
  155.                 }
  156.  
  157.                 if (buf[cpos] == '\n') {
  158.                     (*term.t_putchar)('\b');
  159.                     (*term.t_putchar)('\b');
  160.                     (*term.t_putchar)(' ');
  161.                     (*term.t_putchar)(' ');
  162.                     (*term.t_putchar)('\b');
  163.                     (*term.t_putchar)('\b');
  164.                     --ttcol;
  165.                     --ttcol;
  166.                 }
  167.  
  168.                 (*term.t_flush)();
  169.             }
  170.  
  171.         } else if (c == 0x15 && quotef == FALSE) {
  172.             /* C-U, kill */
  173.             while (cpos != 0) {
  174.                 (*term.t_putchar)('\b');
  175.                 (*term.t_putchar)(' ');
  176.                 (*term.t_putchar)('\b');
  177.                 --ttcol;
  178.  
  179.                 if (buf[--cpos] < 0x20) {
  180.                     (*term.t_putchar)('\b');
  181.                     (*term.t_putchar)(' ');
  182.                     (*term.t_putchar)('\b');
  183.                     --ttcol;
  184.                 }
  185.             }
  186.  
  187.             (*term.t_flush)();
  188.  
  189.         } else if (c == quotec && quotef == FALSE) {
  190.             quotef = TRUE;
  191.         } else {
  192.             quotef = FALSE;
  193.             if (cpos < nbuf-1) {
  194.                 buf[cpos++] = c;
  195.  
  196.                 if ((c < ' ') && (c != '\n')) {
  197.                     (*term.t_putchar)('^');
  198.                     ++ttcol;
  199.                     c ^= 0x40;
  200.                 }
  201.  
  202.                 if (c != '\n')
  203.                     (*term.t_putchar)(c);
  204.                 else {    /* put out <NL> for <ret> */
  205.                     (*term.t_putchar)('<');
  206.                     (*term.t_putchar)('N');
  207.                     (*term.t_putchar)('L');
  208.                     (*term.t_putchar)('>');
  209.                     ttcol += 3;
  210.                 }
  211.                 ++ttcol;
  212.                 (*term.t_flush)();
  213.             }
  214.         }
  215.     }
  216. }
  217.  
  218. /*    ectoc:    expanded character to character
  219.         colapse the CTRL and SPEC flags back into an ascii code   */
  220.  
  221. ectoc(c)
  222.  
  223. int c;
  224.  
  225. {
  226.     if (c & CTRL)
  227.         c = c & ~(CTRL | 0x40);
  228.     if (c & SPEC)
  229.         c= c & 255;
  230.     return(c);
  231. }
  232.  
  233. /*    ctoec:    character to extended character
  234.         pull out the CTRL and SPEC prefixes (if possible)    */
  235.  
  236. ctoec(c)
  237.  
  238. int c;
  239.  
  240. {
  241.         if (c>=0x00 && c<=0x1F)
  242.                 c = CTRL | (c+'@');
  243.         return (c);
  244. }
  245.  
  246. /* get a command name from the command line. Command completion means
  247.    that pressing a <SPACE> will attempt to complete an unfinished command
  248.    name if it is unique.
  249. */
  250.  
  251. int (*getname())()
  252.  
  253. {
  254.     register int cpos;    /* current column on screen output */
  255.     register int c;
  256.     register char *sp;    /* pointer to string for output */
  257.     register NBIND *ffp;    /* first ptr to entry in name binding table */
  258.     register NBIND *cffp;    /* current ptr to entry in name binding table */
  259.     register NBIND *lffp;    /* last ptr to entry in name binding table */
  260.     char buf[NSTRING];    /* buffer to hold tentative command name */
  261.     int (*fncmatch())();
  262.  
  263.     /* starting at the beginning of the string buffer */
  264.     cpos = 0;
  265.  
  266.     /* if we are executing a keyboard macro, fill our buffer from there,
  267.        and attempt a straight match */
  268.     if (kbdmop != NULL) {
  269.         while ((c = *kbdmop++) != '\0')
  270.             buf[cpos++] = c;
  271.  
  272.         buf[cpos] = 0;
  273.  
  274.         /* return the result of a match */
  275.         return(fncmatch(&buf[0]));
  276.     }
  277.  
  278.     /* if we are executing a command line get the next arg and match it */
  279.     if (clexec) {
  280.         if (nxtarg(buf) != TRUE)
  281.             return(FALSE);
  282.         return(fncmatch(&buf[0]));
  283.     }
  284.  
  285.     /* build a name string from the keyboard */
  286.     while (TRUE) {
  287.         c = (*term.t_getchar)();
  288.  
  289.         /* if we are at the end, just match it */
  290.         if (c == 0x0d) {
  291.             buf[cpos] = 0;
  292.  
  293.             /* save keyboard macro string if needed */
  294.             if (kbdtext(&buf[0]) == ABORT)
  295.                 return( (int (*)()) NULL);
  296.  
  297.             /* and match it off */
  298.             return(fncmatch(&buf[0]));
  299.  
  300.         } else if (c == ectoc(abortc)) {    /* Bell, abort */
  301.             ctrlg(FALSE, 0);
  302.             (*term.t_flush)();
  303.             return( (int (*)()) NULL);
  304.  
  305.         } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  306.             if (cpos != 0) {
  307.                 (*term.t_putchar)('\b');
  308.                 (*term.t_putchar)(' ');
  309.                 (*term.t_putchar)('\b');
  310.                 --ttcol;
  311.                 --cpos;
  312.                 (*term.t_flush)();
  313.             }
  314.  
  315.         } else if (c == 0x15) {    /* C-U, kill */
  316.             while (cpos != 0) {
  317.                 (*term.t_putchar)('\b');
  318.                 (*term.t_putchar)(' ');
  319.                 (*term.t_putchar)('\b');
  320.                 --cpos;
  321.                 --ttcol;
  322.             }
  323.  
  324.             (*term.t_flush)();
  325.  
  326.         } else if (c == ' ') {
  327. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  328.     /* attempt a completion */
  329.     buf[cpos] = 0;        /* terminate it for us */
  330.     ffp = &names[0];    /* scan for matches */
  331.     while (ffp->n_func != NULL) {
  332.         if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
  333.             /* a possible match! More than one? */
  334.             if ((ffp + 1)->n_func == NULL ||
  335.                (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
  336.                 /* no...we match, print it */
  337.                 sp = ffp->n_name + cpos;
  338.                 while (*sp)
  339.                     (*term.t_putchar)(*sp++);
  340.                 (*term.t_flush)();
  341.                 return(ffp->n_func);
  342.             } else {
  343. /* << << << << << << << << << << << << << << << << << */
  344.     /* try for a partial match against the list */
  345.  
  346.     /* first scan down until we no longer match the current input */
  347.     lffp = (ffp + 1);
  348.     while ((lffp+1)->n_func != NULL) {
  349.         if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
  350.             break;
  351.         ++lffp;
  352.     }
  353.  
  354.     /* and now, attempt to partial complete the string, char at a time */
  355.     while (TRUE) {
  356.         /* add the next char in */
  357.         buf[cpos] = ffp->n_name[cpos];
  358.  
  359.         /* scan through the candidates */
  360.         cffp = ffp + 1;
  361.         while (cffp <= lffp) {
  362.             if (cffp->n_name[cpos] != buf[cpos])
  363.                 goto onward;
  364.             ++cffp;
  365.         }
  366.  
  367.         /* add the character */
  368.         (*term.t_putchar)(buf[cpos++]);
  369.     }
  370. /* << << << << << << << << << << << << << << << << << */
  371.             }
  372.         }
  373.         ++ffp;
  374.     }
  375.  
  376.     /* no match.....beep and onward */
  377.     (*term.t_beep)();
  378. onward:;
  379.     (*term.t_flush)();
  380. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  381.         } else {
  382.             if (cpos < NSTRING-1 && c > ' ') {
  383.                 buf[cpos++] = c;
  384.                 (*term.t_putchar)(c);
  385.             }
  386.  
  387.             ++ttcol;
  388.             (*term.t_flush)();
  389.         }
  390.     }
  391. }
  392.  
  393. kbdtext(buf)    /* add this text string to the current keyboard macro
  394.            definition                        */
  395.  
  396. char *buf;    /* text to add to keyboard macro */
  397.  
  398. {
  399.     /* if we are defining a keyboard macro, save it */
  400.     if (kbdmip != NULL) {
  401.         if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
  402.             ctrlg(FALSE, 0);
  403.             (*term.t_flush)();
  404.             return(ABORT);
  405.         }
  406.  
  407.         /* copy string in and null terminate it */
  408.         while (*buf)
  409.             *kbdmip++ = *buf++;
  410.         *kbdmip++ = 0;
  411.     }
  412.     return(TRUE);
  413. }
  414.  
  415. /*    GET1KEY:    Get one keystroke. The only prefixs legal here
  416.             are the SPEC and CTRL prefixes.
  417.                                 */
  418.  
  419. get1key()
  420.  
  421. {
  422.     int    c;
  423. #if    AMIGA
  424.     int    d;
  425. #endif
  426.  
  427.     /* get a keystroke */
  428.         c = (*term.t_getchar)();
  429.  
  430. #if RAINBOW
  431.  
  432.         if (c & Function_Key)
  433.                 {
  434.                 int i;
  435.  
  436.                 for (i = 0; i < lk_map_size; i++)
  437.                         if (c == lk_map[i][0])
  438.                                 return lk_map[i][1];
  439.                 }
  440.         else if (c == Shift + 015) return CTRL | 'J';
  441.         else if (c == Shift + 0x7F) return META | 0x7F;
  442. #endif
  443.  
  444. #if    MSDOS
  445.     if (c == 0) {                /* Apply SPEC prefix    */
  446.             c = (*term.t_getchar)();
  447.             if (c>=0x00 && c<=0x1F)        /* control key? */
  448.                     c = CTRL | (c+'@');
  449.         return(SPEC | c);
  450.     }
  451. #endif
  452.  
  453. #if    AMIGA
  454.     /* apply SPEC prefix */
  455.     if ((unsigned)c == 155) {
  456.         c = (*term.t_getchar)();
  457.  
  458.         /* first try to see if it is a cursor key */
  459.         if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
  460.             return(SPEC | c);
  461.  
  462.         /* next, a 2 char sequence */
  463.         d = (*term.t_getchar)();
  464.         if (d == '~')
  465.             return(SPEC | c);
  466.  
  467.         /* decode a 3 char sequence */
  468.         c = d + 32;
  469.         /* if a shifted function key, eat the tilde */
  470.         if (d >= '0' && d <= '9')
  471.             d = (*term.t_getchar)();
  472.         return(SPEC | c);
  473.     }
  474. #endif
  475.  
  476. #if  WANGPC
  477.     if (c == 0x1F) {            /* Apply SPEC prefix    */
  478.             c = (*term.t_getchar)();
  479.         return(SPEC | c);
  480.     }
  481. #endif
  482.  
  483.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  484.                 c = CTRL | (c+'@');
  485.         return (c);
  486. }
  487.  
  488. /*    GETCMD:    Get a command from the keyboard. Process all applicable
  489.         prefix keys
  490.                             */
  491. getcmd()
  492.  
  493. {
  494.     int c;        /* fetched keystroke */
  495.  
  496.     /* get initial character */
  497.     c = get1key();
  498.  
  499.     /* process META prefix */
  500.     if (c == metac) {
  501.         c = get1key();
  502.             if (c>='a' && c<='z')        /* Force to upper */
  503.                     c -= 0x20;
  504.             if (c>=0x00 && c<=0x1F)        /* control key */
  505.                 c = CTRL | (c+'@');
  506.         return(META | c);
  507.     }
  508.  
  509.     /* process CTLX prefix */
  510.     if (c == ctlxc) {
  511.         c = get1key();
  512.             if (c>='a' && c<='z')        /* Force to upper */
  513.                     c -= 0x20;
  514.             if (c>=0x00 && c<=0x1F)        /* control key */
  515.                 c = CTRL | (c+'@');
  516.         return(CTLX | c);
  517.     }
  518.  
  519.     /* otherwise, just return it */
  520.     return(c);
  521. }
  522.  
  523. /*    atoi:    ascii string to integer......for systems without    */
  524.  
  525. atoi(st)
  526.  
  527. char *st;
  528.  
  529. {
  530.     int result;    /* resulting number */
  531.     int sign;    /* sign of resulting number */
  532.     char c;        /* current char being examined */
  533.  
  534.     result = 0;
  535.     sign = 1;
  536.     while ((c = *st++)) {
  537.         if (c == '-')
  538.             sign *= -1;
  539.         if (c >= '0' && c <= '9')
  540.             result = result * 10 + c - '0';
  541.     }
  542.  
  543.     return(result * sign);
  544. }
  545.